namespace Angelus.Data.Linq.OracleClient
{
	using System;
    using System.Data.DLinq.ProviderBase;

    /// <summary>
    /// 
    /// </summary>
    internal static class OracleTypePredictor
    {
        #region Type Predicting Implementation

        /// <summary>
        /// 
        /// </summary>
        /// <param name="typeProvider"></param>
        /// <param name="binary"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        internal static ProviderType PredictTypeForBinary(TypeSystemProvider typeProvider, SqlNodeType binary,
                                                          ProviderType left, ProviderType right)
        {
            int precedence = left.ComparePrecedenceTo(right);
            ProviderType type = (precedence > 0) ? left : right;

            switch (binary)
            {
                case SqlNodeType.Or:
                case SqlNodeType.NE:
                case SqlNodeType.LT:
                case SqlNodeType.GE:
                case SqlNodeType.GT:
                case SqlNodeType.LE:
                case SqlNodeType.EQ:
                case SqlNodeType.And:
                    return typeProvider.GetApplicationType(0);

                case SqlNodeType.Sub:
                    return type;

                case SqlNodeType.Mod:
                    {
                        ProviderType fromType = typeProvider.From(typeof (int));
                        if (fromType.ComparePrecedenceTo(type) <= 0)
                        {
                            return type;
                        }
                        return fromType;
                    }

                case SqlNodeType.Mul:
                    return type;

                case SqlNodeType.Coalesce:
                    return type;

                case SqlNodeType.Concat:
                    return typeProvider.From(typeof (string));

                case SqlNodeType.Div:
                    return type;

                case SqlNodeType.BitAnd:
                case SqlNodeType.BitOr:
                case SqlNodeType.BitXor:
                    return type;

                case SqlNodeType.Add:
                    return type;

                default:
                    throw new Exception("Unhandled operator: " + binary);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="typeProvider"></param>
        /// <param name="unary"></param>
        /// <param name="operand"></param>
        /// <returns></returns>
        internal static ProviderType PredictTypeForUnary(TypeSystemProvider typeProvider, SqlNodeType unary,
                                                         ProviderType operand)
        {
            switch (unary)
            {
                case SqlNodeType.Sum:
                case SqlNodeType.Stddev:
                case SqlNodeType.Covar:
                case SqlNodeType.Avg:
                    return typeProvider.MostPreciseTypeInFamily(operand);

                case SqlNodeType.Treat:
                    return operand;

                case SqlNodeType.ValueOf:
                    return operand;

                case SqlNodeType.Negate:
                    return operand;

                case SqlNodeType.Not:
                case SqlNodeType.IsNotNull:
                case SqlNodeType.IsNull:
                    return typeProvider.GetApplicationType(0);

                case SqlNodeType.Min:
                    return operand;

                case SqlNodeType.Max:
                    return operand;

                case SqlNodeType.Count:
                    return typeProvider.From(typeof (decimal));

                case SqlNodeType.LongCount:
                    return typeProvider.From(typeof (long));

                case SqlNodeType.BitNot:
                    return operand;

                default:
                    throw new Exception("Unhandled operator: " + unary);
            }
        }

        #endregion
    }
}